import { Injectable, Logger } from '@nestjs/common';
import { DataSource } from 'typeorm';
import { SQLDto } from './sql.dto';

@Injectable()
export class AppService {
  private readonly logger = new Logger(AppService.name);

  constructor(private dataSource: DataSource) {}

  /**
   * 处理SQL值
   * @param value
   * @returns
   */
  handleSQLValue(value: any) {
    if (typeof value === 'string') {
      return `'${value}'`;
    }
    if (value === null) {
      return 'NULL';
    }
    return value;
  }

  /**
   * 构建插入语句
   * @param table
   * @param data
   * @returns
   */
  builderInsert(table: string, data: object) {
    const keys = [];
    const values = [];

    for (const key of Object.keys(data)) {
      keys.push(key);
      values.push(this.handleSQLValue(data[key]));
    }

    return `INSERT INTO ${table} (${keys.join(',')}) VALUES (${values.join(
      ',',
    )})`;
  }

  /**
   * 构建删除语句
   * @param table
   * @param where
   * @returns
   */
  builderDelete(table: string, where: string) {
    return `DELETE FROM ${table} WHERE ${where}`;
  }

  /**
   * 构建更新语句
   * @param table
   * @param data
   * @param key
   * @returns
   */
  builderUpdate(table: string, data: object, key: object) {
    const builderParameter = (obj: object, separator: string) =>
      Object.entries(obj)
        .map((v) => {
          return `${v[0]}=${this.handleSQLValue(v[1])}`;
        })
        .join(separator);

    const set = builderParameter(data, ',');
    const where = builderParameter(key, ' AND ');

    return `UPDATE ${table} SET ${set} WHERE ${where}`;
  }

  /**
   * 执行查询语句
   * @param sqlDto
   * @returns
   */
  async query(sqlDto: SQLDto) {
    const { table, action, field, where, data, key, procedure } = sqlDto;
    let query = '';

    switch (action) {
      case 'insert':
        query = this.builderInsert(table, data);
        break;

      case 'delete':
        query = this.builderDelete(table, where);
        break;

      case 'update':
        query = this.builderUpdate(table, data, key);
        break;

      case 'select':
        query = `SELECT ${field} FROM ${table} ${
          where ? 'WHERE ' + where : ''
        }`;
        break;

      case 'exec':
        query = `EXEC ${procedure}`;
        break;

      default:
        break;
    }

    try {
      return await this.dataSource.query(query);
    } catch (error) {
      this.logger.error(`${error.message} SQL: ${query}`);
      throw error;
    }
  }
}
